package com.yupi.springbootinit.bizmq;

import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import com.rabbitmq.client.Channel;
import com.yupi.springbootinit.common.ChartStatus;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.constant.MqConstant;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.manager.BigModelNew;
import com.yupi.springbootinit.model.entity.Chart;
import com.yupi.springbootinit.model.entity.User;
import com.yupi.springbootinit.service.ChartService;
import com.yupi.springbootinit.service.UserService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;

import static com.yupi.springbootinit.constant.RedisConstants.CACHE_ALL_CHART;
import static com.yupi.springbootinit.constant.RedisConstants.CACHE_MY_CHART;

@Component
@Slf4j
public class BiMessageConsumer {

    @Resource
    private ChartService chartService;
    @Resource
    private BigModelNew bigModelNew;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private UserService userService;

    /**
     * 接收消息的方法
     *
     * @param csvData       消息内容，要发送的具体消息 csvData excel文件解析后的文本
     * @param channel      消息所在的通道，可以通过该通道与 RabbitMQ 进行交互，例如手动确认消息、拒绝消息等
     * @param deliveryTag  消息的投递标签，用于唯一标识一条消息
     * @param chartId  当前文件生成的图表id
     *
     */
    @SneakyThrows
    // 设置消息的确认机制为手动确认
    @RabbitListener(queues = {MqConstant.QUEUE_NAME}, ackMode = "MANUAL")
    // @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag是一个方法参数注解,用于从消息头中获取投递标签(deliveryTag),
    //deliveryTag 区分每条不同的消息
    // 通过使用@Header(AmqpHeaders.DELIVERY_TAG)注解,可以从消息头中提取出该投递标签,并将其赋值给long deliveryTag参数。
    public void receiveMessage(
            @Payload String csvData,  //csvData
            Channel channel,
            @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
            @Header("userId") String userId,
            @Header("chartId") String chartId) {  //图表id

        if(StringUtils.isBlank(csvData) || StringUtils.isBlank(chartId)){
            //  mq 拒绝请求,丢弃当前消息
            channel.basicNack(deliveryTag,false,false);  // b1 消息会被直接丢弃   b1:true 不断监听后再消费
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        log.info("receiveMessage csvData = {}", csvData);
        log.info("receiveMessage chartId = {}", chartId);

        Chart chart = chartService.getById(chartId);
        if(chart == null){
            channel.basicNack(deliveryTag,false,false);
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }


        //防止消息重复消费
        if(StringUtils.isNotBlank(chart.getGenChart()) || StringUtils.isNotBlank(chart.getGenResult())){
            channel.basicNack(deliveryTag,false,false);
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long newChartId = Long.valueOf(chartId);
        //ai处理由异步化执行
        //开始请求时，处理状态为处理中
        Chart charting = new Chart();
        charting.setId(newChartId);
        charting.setStatus(ChartStatus.RUNNING.toString());
        boolean saveing = chartService.updateById(charting);
        if(!saveing) {
            handleChartUpdateError(newChartId,"图表处理中...状态更新失败");
        }
        String userInput = builtUserInput(chart, csvData);

        //获取ai答复，并处理文本
        String result = bigModelNew.sendMessageToXingHuo(userInput);
        String[] splits = result.split("'【'");
        if(splits.length < 2){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"AI异常，请重试");
        }
        String genChart = splits[1].trim();
        String genResult = splits[2].trim();

        //格式化json字符串，保证页面正确显示
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String formattedJson = gson.toJson(JsonParser.parseString(genChart));

        //请求后，处理状态为成功
        Chart charted = new Chart();
        charted.setId(newChartId);
        charted.setGenChart(formattedJson);
        charted.setGenResult(genResult);
        charted.setStatus(ChartStatus.SUCCEED.toString());
        boolean saved = chartService.updateById(charted);
        if(!saved) {
            handleChartUpdateError(newChartId,"图表成功状态更新失败");
        }

        //添加成功，删除页缓存
        //判断当前用户角色，普通用户添加图表，则删除当前用户和 管理员分页键，管理员添加图表，仅删除管理员的键
        User user = userService.getById(userId);
        Set<String> allKeys = new HashSet<>();
        if("user".equals(user.getUserRole())) {
            String key1 = CACHE_MY_CHART+user.getId()+"_*";
            String key2 = CACHE_ALL_CHART +"*";
            Set<String>  keys1 = stringRedisTemplate.keys(key1);
            Set<String>  keys2 = stringRedisTemplate.keys(key2);
            allKeys.addAll(keys2);
            allKeys.addAll(keys1);
        }
        if("admin".equals(user.getUserRole())) {
            String key = CACHE_ALL_CHART+"*";
            allKeys = stringRedisTemplate.keys(key);
        }

        if(allKeys != null && !allKeys.isEmpty()){
            stringRedisTemplate.delete(allKeys);
        }

        // 手动确认消息的接收，队列删除该消息
        channel.basicAck(deliveryTag, false);
    }


    /**
     * 处理请求失败，更新图表状态，失败信息
     * @param charId
     * @param execMessage
     */
    public void handleChartUpdateError(long charId,String execMessage) {
        Chart chartError= new Chart();
        chartError.setId(charId);
        chartError.setExecMessage(execMessage);
        chartError.setStatus(ChartStatus.FAILED.toString());
        boolean saved = chartService.updateById(chartError);
        if(!saved){
            log.info("图表失败状态更新失败。id: "+charId+execMessage);
        }
    }

    public String builtUserInput(Chart chart,String csvData){

        String chartType = chart.getChartType();
        String userGoal = chart.getGoal();

        StringBuilder userInput = new StringBuilder();
        userInput.append("分析需求：").append("\n");
        if(StrUtil.isNotBlank(chartType)){
            userGoal += "请使用" + chartType;
        }
        userInput.append(userGoal).append("\n");
        userInput.append("原始数据：").append("\n");
        //将excel文本处理为csv数据(压缩精简excel数据)，便于ai分析

        log.info("csv数据展示：{}",csvData);
        userInput.append(csvData).append("\n");
        return userInput.toString();
    }
}
